#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'tian'
__data__ = '2021/9/26 16:18'
# software: PyCharm

import random

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from django.conf import settings

from apps.web import models
from apps.web.forms.bootstrap import BootStrapForm
from utils.tencent.sms import send_sms_single
from utils import encrypt


class RegFormModel(BootStrapForm, forms.ModelForm):
    """
    注册验证
    """
    pwd = forms.CharField(
        label="密码",
        min_length=6,
        max_length=64,
        error_messages={
            "min_length": "密码不能小于6个字符",
            "max_length": "密码不能大于64个字符"
        },
        validators=[RegexValidator(r'^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]{6,64}$', "密码必须包含数字和字母"), ],
        widget=forms.PasswordInput()
    )
    re_pwd = forms.CharField(
        label="重复密码",
        min_length=6,
        max_length=64,
        error_messages={
            "min_length": "密码不能小于6个字符",
            "max_length": "密码不能大于64个字符"
        },
        widget=forms.PasswordInput()
    )
    code = forms.CharField(
        label="验证码",
    )
    mobile_phone = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机格式有误"), ]

    )

    class Meta:
        model = models.UserInfo
        fields = ["user", "email", "pwd", "re_pwd", "mobile_phone", "code"]

    def clean_user(self):
        """
        用户名不能重名的局部钩子
        :return:
        """
        username = self.cleaned_data.get("user")
        exists = models.UserInfo.objects.filter(user=username).exists()
        if exists:
            raise ValidationError("用户名已存在")
        return username

    def clean_email(self):
        """
        邮箱不能重复
        :return:
        """
        email = self.cleaned_data.get("email")
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError("邮箱已存在")
        return email

    def clean_pwd(self):
        """
        加密&返回
        :return:
        """
        pwd = self.cleaned_data.get("pwd")
        return encrypt.md5(pwd)

    def clean_re_pwd(self):
        """
        获取用户输入的两次密码
        :return:
        """
        pwd = self.cleaned_data.get("pwd")
        re_pwd = encrypt.md5(self.cleaned_data.get("re_pwd"))
        if pwd != re_pwd:
            raise ValidationError("两次密码不一致")
        return re_pwd

    def clean_mobile_phone(self):
        """
        手机号是否已经注册校验
        :return:
        """
        mobile_phone = self.cleaned_data.get("mobile_phone")
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError("手机号已注册")
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data.get('code')
        mobile_phone = self.cleaned_data.get("mobile_phone")
        if not mobile_phone:
            return code
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode("utf-8")
        if code.strip() != redis_str_code:
            raise ValidationError("验证码错误，请重新输入")
        return code


class SendSmsForm(forms.Form):
    """
    手机验证码
    """

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    mobile_phone = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机格式错误"), ]
    )

    def clean_mobile_phone(self):
        """
        手机号校验的钩子
        :return:
        """
        mobile_phone = self.cleaned_data.get("mobile_phone")

        # 判断短信模板是否有问题
        tpl = self.request.GET.get("tpl")
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            raise ValidationError("短信模板错误")
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == "login":
            if not exists:
                raise ValidationError("手机号不存在")
        else:
            if exists:
                raise ValidationError("手机号码已注册")

        code = random.randrange(1000, 9999)
        print("验证码", code)
        # 发送短信
        # sms = send_sms_single(mobile_phone, template_id, [code, ])
        # if sms['result'] != 0:
        #     raise ValidationError("短信发送失败，{}".format(sms['errmsg']))

        # 验证码写入redis
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone


class LoginForm(BootStrapForm, forms.Form):
    """
    用户名和密码登录页面
    """
    # print(dir(forms.Form))

    username = forms.CharField(label="手机号或邮箱")
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True)  # 输入错误密码后保留原密码
    )
    code = forms.CharField(label="图片验证码")

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        # 加密 & 返回
        return encrypt.md5(pwd)

    def clean_code(self):
        """
        校验图片验证码是否正确
        :return:
        """
        code = self.cleaned_data.get("code")
        session_code = self.request.session.get("image_code")
        if not session_code:
            raise ValidationError("验证码已过期,请重新获取")
        if code.strip().upper() != session_code.strip().upper():
            raise ValidationError("验证码输入错误")
        return code


class LoginSmsForm(BootStrapForm, forms.Form):
    """
    登录
    """
    mobile_phone = forms.CharField(
        label="手机号码",
        validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号码格式错误'), ])

    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput())

    def clean_mobile_phone(self):
        """
        手机号码存在，将当前用户对象返回
        :return:
        """
        mobile_phone = self.cleaned_data.get("mobile_phone")
        user_obj = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_obj:
            raise ValidationError("手机号码不存在")
        return user_obj

    def clean_code(self):
        """
        校验验证码
        :return:
        """
        code = self.cleaned_data.get("code")
        user_obj = self.cleaned_data.get("mobile_phone")
        if not user_obj:
            return code
        conn = get_redis_connection()
        redis_code = conn.get(user_obj.mobile_phone)
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode("utf-8")
        if code.strip() != redis_str_code:
            raise ValidationError("验证码错误，请重新输入")
        return code
